<?php

namespace JsonLowCode\Traits;

use Closure;
use JsonLowCode\Schema;
use JsonLowCode\Support\Js;
use JsonLowCode\Helps\Random;
use JsonLowCode\Support\JsParse;
use JsonLowCode\UI\Html;
use JsonLowCode\UI\Template;

/**
 * 组件基础 trait
 * BaseSchema
 */
trait HasSchema
{


    /**
     * 设置组件名称
     * @param string $name
     * @return $this
     */
    public function componentName(string $name): static
    {
        $this->componentName = $name;
        return $this->setAttribute('componentName',$name);
    }


    /**
     * 设置组件显示条件
     * @param bool|string $bool
     * @return $this
     */
    public function condition(bool|string $bool = true): static
    {
        return $this->setAttribute('condition',$bool);
    }


    /**
     * @param string $prop
     * @param string $value
     * @param bool $isJSExpression true:js表达式,false:js函数体
     * @param Closure|null $closure
     * @return $this
     */
    public function bind(string $prop, string $value, bool $isJSExpression = true, Closure $closure = null): static
    {
        $parseValue = $isJSExpression?JsParse::jsExpression($value):JsParse::JSFunction($value);
        if ($closure!==null) $closure($parseValue,$this);
        return $this->prop($prop,$parseValue);
    }

    /**
     * @param string $prop
     * @param string $value 绑定变量事件
     * @param Closure|null $closure
     * @return $this
     */
    public function bindExpression(string $prop, string $value, Closure $closure = null): static
    {
        $parseValue = JsParse::JSExpression($value);
        if ($closure!==null) $closure($parseValue,$this);
        return $this->prop($prop,$parseValue);
    }

    /**
     * @param string $prop
     * @param string $value 绑定变量事件
     * @param Closure|null $closure
     * @return $this
     */
    public function bindFunction(string $prop, string $value, Closure $closure = null): static
    {
        $parseValue = JsParse::JSFunction($value);
        if ($closure!==null) $closure($parseValue,$this);
        return $this->prop($prop,$parseValue);
    }


    /**
     * 设置组件slot 方式一
     * @param string $slotName
     * @param mixed $schema
     * @param array $params
     * @return $this
     */
    public function slot(string $slotName, mixed $schema = null, array $params = []): static
    {
        $template = new Template($slotName, $params);
        if($schema!==null){
            $template->children($schema);
        }
        return $this->children($template);
    }

    /**
     * 设置组件循环数据
     * @param array|string $data
     * @return $this
     */
    public function loop(array|string $data = []): static
    {
        $this->setAttribute("loop",$data);
        return $this;
    }

    /**
     * 设置组件循环参数
     * @param string $itemKey
     * @param string $indexKey
     * @return $this
     */
    public function loopArgs(string $itemKey = 'item', string $indexKey = 'index'): static
    {
        $this->setAttribute("loopArgs",[$itemKey,$indexKey]);
        return $this;
    }

    /**
     * @param $text
     * @return Html
     */
    private function makeSpan($text): Html
    {
        return Html::span($text);
    }

    /**
     * 设置组件子元素
     * @param mixed $children
     * @return $this
     */
    public function children(mixed $children = null): static
    {
        if(is_null($children)) return $this;
        if ($children instanceof JsParse){
            $this->children = $children;
            return $this->setAttribute("children",$this->children);
        }
        $collects = $this->children??[];
        if (!is_array($collects)){
            $collects = [$collects];
        }
        if ($collects && $children){
            if (count($collects)==1&&is_scalar($collects[0])){
                $collects = [$this->makeSpan($collects[0])];
            }
        }
        if($children instanceof Closure){
            $result = $children($this);
            if ($result){
                $collects[] = $result;
            }
        }elseif(is_array($children)){
            $collects = array_merge($collects, $children);
        }elseif($children instanceof Schema){
            $collects[] = $children;
        }else{
            if (is_scalar($children)){
                if ($children===0.0){
                    $children = "0.0";
                }elseif ($children===0.00){
                    $children = "0.00";
                }else{
                    $children = strval($children);
                }
//                if (str_contains($children,"this.")||str_contains($children,"state.")){
//                    if (str_contains($children,"{{")&&str_contains($children,"}}")){
//                        $children = "{{{$children}}}";
//                    }else{
//                        $children = "{{{$children}}}";
//                    }
//                }
            }
            if ($collects){
                $collects[] = $this->makeSpan($children);
            }else{
                $collects[] = $children;
            }
        }
        if ($collects){
            if (count($collects)==1&&is_scalar($children)){
                $this->children = $collects[0];
            }else{
                $this->children = $collects;
            }
            return $this->setAttribute("children",$this->children);
        }
        return $this;
    }

    /**
     * slot default 设置子根元素
     * @param mixed $children
     * @param array<int,string> $params
     * @return $this
     */
    public function slotDefault(mixed $children = null, array $params = []): static
    {
        $this->children = null;
        $this->setAttribute("children",$this->children);
        return $this->slot("default", $children, $params);
    }




    /**
     * 获取父级
     * @return Schema|null
     */
    public function getParent(): ?Schema
    {
        return $this->parent;
    }

    /**
     * @param Schema|null $parent
     * @return $this
     */
    public function setParent(Schema $parent = null): static
    {
        $this->parent = $parent;
        return $this;
    }

    /**
     * @param string|null $expose
     * @return string
     */
    public function exposes(string $expose = null): string
    {
        $ref = $this->getRef();
        if (!$ref){
            $ref = Random::alpha()."Ref";
            $this->ref($ref);
        }
        if ($expose){
            $bindJs = Js::this("$('{$ref}').$expose");
        }else{
            $bindJs = Js::this("$('{$ref}')");
        }
        return $bindJs;
    }
}
